#ifndef _QUEUE__H_
#define _QUEUE__H_

#include <stdio.h>
#include <cstdlib> 
#include <pthread.h>
#include <errno.h>
#include <csp_debug.h>

template <class Type> class Queue;			
template <class Type> class _queue_item {
	Type *value;
	_queue_item *next;
	_queue_item() { next=NULL;};
	_queue_item(Type &val) { 
		value=&val;
		next=NULL;
	};
	Type & getValue(){
		Type &tmp = *value;
		return tmp;
	}
	~_queue_item() {};
	void DeleteQueue() {					
		if(next!=NULL) next->DeleteQueue();
		delete this;
	};
	friend class Queue<Type>;				 
											
};

template <class Type> class Queue {
	private:
	public:
	_queue_item<Type> *first;				
	_queue_item<Type> *last;				
	unsigned int s;
/*
	pthread_mutex_t  mutex;
	pthread_cond_t non_empty_cv;
*/
	~Queue();
	Queue();
	int size();
	Type & pop();
	void push(Type & item);
};

template <class Type>
void Queue<Type>::push(Type & item) {					
/*
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(1);
	}
*/
	_queue_item<Type> *next=new _queue_item<Type> (item);
	if (first==NULL) 
		last=first=next;
	else {
		last->next=next;
		last=next;
	}
	s++;
/*
	if(0 < s){
		pthread_cond_signal(&non_empty_cv);
	}
	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(1);
	}
*/
}

template <class Type>
Type & Queue<Type>::pop() {							
/*
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(1);
	}
	while(0 >= s){
		pthread_cond_wait(&non_empty_cv, &mutex);
	}
*/
	s--;
	_queue_item<Type> *oldFirst=first;

	Type &val=first->getValue();
	first=first->next;
	delete oldFirst;
/*
	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(1);
	}
*/
	return val;
}

template <class Type>
int Queue<Type>::size(){
	int i;
/*
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(1);
	}
*/
	i = s;
/*
	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(1);
	}
*/
	return i;
}

template <class Type>
Queue<Type>::Queue() {
/*
	if(pthread_mutex_init(&mutex, NULL) || pthread_cond_init(&non_empty_cv, NULL)){
		perror("Init of mutex failed.");
		exit(1);
	}
*/
	s = 0;
	first=last=NULL;
}

template <class Type>
Queue<Type>::~Queue() {	
/*
	if(pthread_mutex_lock(&mutex)){
		perror("Locking failed");
		exit(1);
	}
*/
	if(first!=NULL){
		first->DeleteQueue();
	}
/*
	if(pthread_mutex_unlock(&mutex)){
		perror("Unlocking failed");
		exit(1);
	}
	pthread_mutex_destroy(&mutex);
*/
}


#endif 
